package com.xiaotao.graphql.controller;

import com.netflix.graphql.dgs.*;
import com.xiaotao.graphql.dataloader.PhoneDataLoader;
import com.xiaotao.graphql.pojo.Phone;
import com.xiaotao.graphql.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.dataloader.DataLoader;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author xiaotao
 */
@Slf4j
@DgsComponent
public class UserFetcher {

    /**
     * 用户列表集合
     */
    public static List<User> userList = new ArrayList<>();
    /**
     * 手机列表集合
     */
    public static List<Phone> phoneList = new ArrayList<>();

    static{

        //初始化用户列表集合
        User user1 = new User();
        user1.setUserId("zhangsan");
        user1.setUserName("张三");
        userList.add(user1);

        User user2 = new User();
        user2.setUserId("lisi");
        user2.setUserName("李四");
        userList.add(user2);

        //初始化手机列表集合
        Phone phone1 = new Phone();
        phone1.setPhoneId("huawei");
        phone1.setPhoneName("华为");
        phone1.setUserId("zhangsan");
        phoneList.add(phone1);

        Phone phone2 = new Phone();
        phone2.setPhoneId("xiaomi");
        phone2.setPhoneName("小米");
        phone2.setUserId("zhangsan");
        phoneList.add(phone2);

        Phone phone3 = new Phone();
        phone3.setPhoneId("hongmi");
        phone3.setPhoneName("红米");
        phone3.setUserId("lisi");
        phoneList.add(phone3);
    }

    @DgsQuery
    public List<User> userQuery(@InputArgument("userIdList") List<String> userIdList){
        List<User> list = new ArrayList<>();

        for(User a :userList){
            for(String b:userIdList){
                if(a.getUserId().equals(b)){
                    list.add(a);
                }
            }
        }

        log.debug("姓名查询方法被执行");
        return list;

    }

    /**
     * 原始方法的实现（和java实现没啥区别，体会不出父子对象之间的关系和异步加载）
     * @param
     */
    private void getPhoneInfo(List<User> userList){

        List<Phone> list = new ArrayList<>();


        Map<String, List<Phone>> map = list.stream().collect(Collectors.groupingBy(Phone::getUserId));

        for(User a: userList){
            if(map.containsKey(a.getUserId())){
                List<Phone> phones = map.get(a);
                a.setUserPhoneList(phones);
            }
        }

        System.out.println("1-同步获取用户的手机方法被执行");

    }

    /**
     * 前端入参不需要这个返回值，是不会执行查询方法的。
     * 缺点：n+1问题，集合入参会被循环调用。示例入参：
     * @annotation DgsData：字段解析器。parentType:父节点类型 field：父节点对象字段名
     * @param dfe dgs运行期帮我们自动注入的对象，用来拿参数
     * @return
     */
    //@DgsData(parentType = "User",field = "phoneList")
    public List<Phone> getPhone(DgsDataFetchingEnvironment dfe){
        System.out.println("2-同步获取用户手机信息被执行");

        List<Phone> resultList = new ArrayList<>();
        User user = dfe.getSource();

        for(Phone a:phoneList){
            if(a.getUserId().equals(user.getUserId())){
                resultList.add(a);
            }
        }
        return resultList;

    }

    /**
     * 前端入参不需要这个返回值，是不会执行查询方法的。与上面的方法不同的是：
     *      1.多线程获取。
     *      2.解决n+1问题。
     * @annotation DgsData：字段解析器 parentType:父节点类型 field：父节点对象字段名
     * @param dfe dgs运行期帮我们自动注入的对象，用来拿参数
     * @return
     */
    @DgsData(parentType = "User",field = "userPhoneList")
    public CompletableFuture<Phone> PhoneList(DgsDataFetchingEnvironment dfe){

        User User = dfe.getSource();
        DataLoader<String,Phone> dataLoader = dfe.getDataLoader(PhoneDataLoader.class);
        return dataLoader.load(User.getUserId());

    }

}
